import 'dart:async';

import 'package:flutter/services.dart';

import '../public/util/log_util.dart';
import 'flutter_sound_platform_interface.dart';
import 'flutter_sound_recorder_platform_interface.dart';

const MethodChannel _channel =
    MethodChannel('com.dooboolab.flutter_sound_recorder');

/// An implementation of [UrlLauncherPlatform] that uses method channels.
class MethodChannelFlutterSoundRecorder extends FlutterSoundRecorderPlatform {
  /*ctor */ MethodChannelFlutterSoundRecorder() {
    _setCallback();
  }

  void _setCallback() {
    //channel = const MethodChannel('com.dooboolab.flutter_sound_recorder');
    _channel.setMethodCallHandler((MethodCall call) {
      return channelMethodCallHandler(call)!;
    });
  }

  Future<dynamic>? channelMethodCallHandler(MethodCall call) {
    var aRecorder =
        getSession(call.arguments['slotNo'] as int);
    //bool? success = call.arguments['success'] as bool?;
    var success = call.arguments['success'] != null
        ? call.arguments['success'] as bool
        : false;

    switch (call.method) {
      case 'updateRecorderProgress':
        {
          aRecorder!.updateRecorderProgress(
              duration: call.arguments['duration'],
              dbPeakLevel: call.arguments['dbPeakLevel']);
        }
        break;

      case 'recordingData':
        {
          aRecorder!.recordingData(data: call.arguments['recordingData']);
        }
        break;

      case 'startRecorderCompleted':
        {
          aRecorder!.startRecorderCompleted(call.arguments['state'], success);
        }
        break;

      case 'stopRecorderCompleted':
        {
          aRecorder!.stopRecorderCompleted(
              call.arguments['state'], success, call.arguments['arg']);
        }
        break;

      case 'pauseRecorderCompleted':
        {
          aRecorder!.pauseRecorderCompleted(call.arguments['state'], success);
        }
        break;

      case 'resumeRecorderCompleted':
        {
          aRecorder!.resumeRecorderCompleted(call.arguments['state'], success);
        }
        break;

      case 'openRecorderCompleted':
        {
          aRecorder!.openRecorderCompleted(call.arguments['state'], success);
        }
        break;

      case 'closeRecorderCompleted':
        {
          aRecorder!.closeRecorderCompleted(call.arguments['state'], success);
        }
        break;

      case 'log':
        {
          log(call.arguments['msg']);
        }
        break;

      default:
        throw ArgumentError('Unknown method ${call.method}');
    }

    return null;
  }

  Future<void> invokeMethodVoid(FlutterSoundRecorderCallback callback,
      String methodName, Map<String, dynamic> call) {
    call['slotNo'] = findSession(callback);
    return _channel.invokeMethod(methodName, call);
  }

  Future<int?> invokeMethodInt(FlutterSoundRecorderCallback callback,
      String methodName, Map<String, dynamic> call) {
    call['slotNo'] = findSession(callback);
    return _channel.invokeMethod(methodName, call);
  }

  Future<bool> invokeMethodBool(FlutterSoundRecorderCallback callback,
      String methodName, Map<String, dynamic> call) async {
    call['slotNo'] = findSession(callback);
    var r = await _channel.invokeMethod(methodName, call) as bool;
    return r;
  }

  Future<String?> invokeMethodString(FlutterSoundRecorderCallback callback,
      String methodName, Map<String, dynamic> call) {
    call['slotNo'] = findSession(callback);
    return _channel.invokeMethod(methodName, call);
  }

  @override
  Future<void>? resetPlugin(
    FlutterSoundRecorderCallback callback,
  ) {
    return invokeMethodVoid(
      callback,
      'resetPlugin',
      <String, dynamic>{},
    );
  }

  @override
  Future<void> openRecorder(FlutterSoundRecorderCallback callback) {
    return invokeMethodVoid(
      callback,
      'openRecorder',
      {},
    );
  }

  @override
  Future<void> closeRecorder(
    FlutterSoundRecorderCallback callback,
  ) {
    return invokeMethodVoid(
      callback,
      'closeRecorder',
      <String, dynamic>{},
    );
  }

  @override
  Future<bool> isEncoderSupported(
    FlutterSoundRecorderCallback callback, {
    AudioCodec codec = AudioCodec.defaultCodec,
  }) {
    return invokeMethodBool(
      callback,
      'isEncoderSupported',
      {
        'codec': codec.index,
      },
    );
  }

  @override
  Future<void> setSubscriptionDuration(
    FlutterSoundRecorderCallback callback, {
    Duration? duration,
  }) {
    return invokeMethodVoid(
      callback,
      'setSubscriptionDuration',
      {'duration': duration!.inMilliseconds},
    );
  }

  @override
  Future<void> startRecorder(
    FlutterSoundRecorderCallback callback, {
    String? path,
    int? sampleRate,
    int? numChannels,
    int? bitRate,
    AudioCodec? codec,
    bool? toStream,
    AudioSource? audioSource,
  }) {
    return invokeMethodVoid(
      callback,
      'startRecorder',
      {
        'path': path,
        'sampleRate': sampleRate,
        'numChannels': numChannels,
        'bitRate': bitRate,
        'codec': codec!.index,
        'toStream': toStream! ? 1 : 0,
        'audioSource': audioSource!.index,
      },
    );
  }

  @override
  Future<void> stopRecorder(
    FlutterSoundRecorderCallback callback,
  ) {
    return invokeMethodVoid(
      callback,
      'stopRecorder',
      <String, dynamic>{},
    );
  }

  @override
  Future<void> pauseRecorder(
    FlutterSoundRecorderCallback callback,
  ) {
    return invokeMethodVoid(
      callback,
      'pauseRecorder',
      <String, dynamic>{},
    );
  }

  @override
  Future<void> resumeRecorder(
    FlutterSoundRecorderCallback callback,
  ) {
    return invokeMethodVoid(
      callback,
      'resumeRecorder',
      <String, dynamic>{},
    );
  }

  @override
  Future<bool?> deleteRecord(
      FlutterSoundRecorderCallback callback, String path) {
    return invokeMethodBool(callback, 'deleteRecord', {'path': path});
  }

  @override
  Future<String?> getRecordURL(
      FlutterSoundRecorderCallback callback, String path) {
    return invokeMethodString(callback, 'getRecordURL', {'path': path});
  }
}
